
// server.cc 
//	Central server is used to communicate with all clients
//	using the Post Office to coordinate delivery.

// Copyright (c) fishmanager - Student of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include "server.h"
#include <time.h>
#define LOCK_TABLE_SIZE 1024
#define CV_TABLE_SIZE 1024
#define MV_TABLE_SIZE 1024

static char rpc_buffer[MaxMailSize];	// buffer used to receive client message
static char s_buffer[MaxMailSize];		// buffer used to receive server message
static PacketHeader outPktHdr, inPktHdr, s_outPktHdr, s_inPktHdr;		// first two used in total ordering thread, last two used in message forwarding thread
static MailHeader outMailHdr, inMailHdr, s_outMailHdr, s_inMailHdr;		// first two used in total ordering thread, last two used in message forwarding thread

static KernelServerLock ** ServerLockTable;	// server specific lock table
static KernelServerCV ** ServerCVTable;		// server specific condition variable table
static KernelServerMV ** ServerMVTable;		// server specific monitor variable table

static int nextLockIndex = 0;				// next available slot for lock table
static int nextCVIndex = 0;					// next available slot for condition variable table
static int nextMVIndex = 0;					// next available slot for monitor variable table

/**
 * Code for Project 4
 */
static List * msgQueue;		// sorted message queue, each message has been appended the client machineID & mailboxID as well as a timestamp
static int64_t * LTR;		// last timestamp received

//int netname;				// server machine ID
int serverForwardMID;		// ID of server machine which forwarded client message

class Message{
public:
	Message(int m, int b):machine(m), mailbox(b){}
	int machine;
	int mailbox;
};

class ServerMsg{
public:
	ServerMsg(char* m, int len):msg(m),msg_len(len){}
	char * msg;
	int msg_len;
};

//--------------------------------------
//	Utility
//--------------------------------------

unsigned int getCurTime()
{
	unsigned int t;
	struct timeval tempo;
	gettimeofday(&tempo, NULL);
	t = (tempo.tv_sec%100000)*10000 + tempo.tv_usec/100;	//time stampt = time in second * 1000 + milisecond; this is used to prevent overflow
	//ASSERT(t>=0);
	return t;
}





//--------------------------------------
// ServerLock Implementation
//--------------------------------------

ServerLock::ServerLock(char * debugName){
	name = debugName;
	waitQueue = new List;
	machineID = -1;
	mailboxID = -1;
	busy = false;
}

ServerLock::~ServerLock(){
	delete waitQueue;
}

char * ServerLock::Acquire(int mID,  int bID){
	if(isHeldByCurrentNode(mID, bID)){
		DEBUG('v', "machine (%d,%d) is requesting lock(%s) that it has aready acquired\n", mID, bID, name);
		return "032machine has aready hold the lock";
	}
	
	if(!busy){
		busy = true;
		machineID = mID;
		mailboxID = bID;
		DEBUG('v', "machine (%d,%d) acquired lock(%s) successfully\n", mID, bID, name);
		return "1";
	} 
	
	else{
		waitQueue->Append((void *)new Message(mID, bID));
		DEBUG('v', "machine (%d,%d) acquired lock(%s) failed, other one(%d,%d) is using it\n", mID, bID, name, machineID, mailboxID);
		return NULL;
	}
}

char * ServerLock::Release(int mID, int bID){
	if(!isHeldByCurrentNode(mID, bID)){
		DEBUG('v', "machine (%d,%d) is not the owner of lock(%s), cannot release it\n", mID, bID, name);
		return "032machine is not the owner of lock";
	}
    Message * msg = (Message*) waitQueue->Remove();
    if(msg != NULL){
		int mID2 = msg->machine;
		int bID2 = msg->mailbox;
		DEBUG('v', "machine (%d,%d) hands over lock(%s) to machine(%d,%d)\n", mID, bID, name, mID2, bID2);
		delete msg;
		machineID = mID2;
		mailboxID = bID2;
		
		// Send reply to mID2
		char * reply = "1";
		outPktHdr.to = mID2;
		outMailHdr.to = bID2;
		outMailHdr.length = strlen(reply) + 1;
		
		if(netname == serverForwardMID){
		bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
		if ( !success ) {
			printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
			interrupt->Halt();
		}}

		
	} else {
		DEBUG('v', "machine (%d,%d) reset lock(%s) because no one is waiting\n", mID, bID, name);
		busy = false;
		machineID = -1;
		mailboxID = -1;
	}
	
	return "1";
}


bool ServerLock::isHeldByCurrentNode(int mID, int bID){
	return (machineID==mID)&&(mailboxID==bID);
}



//---------------------------------------------
// ServerCV Implementation 
//---------------------------------------------
ServerCV::ServerCV(char * debugName){
	name = debugName;
	lock = -1;
	waitQueue = new List;
}

ServerCV::~ServerCV(){
	delete waitQueue;		 
}

char * ServerCV::Wait(int lockID, int mID, int bID){
	// NOTE: lockID has been checked to be validate lockID
	ServerLock * conditionLock = ServerLockTable[lockID]->lock;
	if(conditionLock == NULL){
		DEBUG('v',"lock requested by machine(%d,%d) is null, can't wait\n", mID, bID);
		return "029lock is null, failing waiting";
	}
	if(!conditionLock->isHeldByCurrentNode(mID, bID)){
		DEBUG('v', "machine(%d,%d) is not holding lock(%s), can't wait\n", mID, bID, conditionLock->getName());
		return "032lock is not hold by current node";
	}
	if(lock == -1){
		lock = lockID;
		DEBUG('v', "machine(%d,%d) register lock(%s) on condition(%s)\n", mID, bID, conditionLock->getName(), name);
	}
	if(lock != lockID){
		DEBUG('v', "machine(%d,%d) is not lock(%s) related, can't wait\n", mID, bID, conditionLock->getName());
		return "035condition is using a different lock";
	}
	
	// machine is going to wait on condition
	DEBUG('v', "machine(%d,%d) is going to wait on condition(%s)\n", mID, bID, name);
	waitQueue->Append((void*)new Message(mID, bID));
	conditionLock->Release(mID, bID);
	
	return NULL;
}

char * ServerCV::Signal(int lockID, int mID, int bID){
	ServerLock * conditionLock = ServerLockTable[lockID]->lock;

	if(conditionLock == NULL){
		DEBUG('v',"lock requested by machine(%d,%d) is null, can't signal\n", mID, bID);
		return "028lock is null, failing signal";
	}
	if(!conditionLock->isHeldByCurrentNode(mID, bID)){
		DEBUG('v', "machine(%d,%d) is not holding lock(%s), can't signal\n", mID, bID, conditionLock->getName());
		return "032lock is not hold by current node";
	}

	if(lock == -1){
		DEBUG('v', "machine(%d,%d) is not lock(%s) related, can't signal\n", mID, bID, conditionLock->getName());
		return "1";
	}
	else if(lock != lockID){
		DEBUG('v', "machine(%d,%d) is not lock(%s) related, can't signal\n", mID, bID, conditionLock->getName());
		return "035condition is using a different lock";
	}

	// machine is going to signal a condition
	DEBUG('v', "machine(%d,%d) is going to signal condition(%s)\n", mID, bID, name);
	Message * msg = (Message*)waitQueue->Remove();
	if(msg != NULL){
		int mID2 = msg->machine;
		int bID2 = msg->mailbox;
		delete msg;
		conditionLock->Acquire(mID2, bID2);
	} 
	
	if(waitQueue -> IsEmpty())
		lock = -1;
		
	return "1";

}

char * ServerCV::Broadcast(int lockID, int mID, int bID){
	ServerLock * conditionLock = ServerLockTable[lockID]->lock;

	if(conditionLock == NULL){
		DEBUG('v',"lock requested by machine(%d,%d) is null, can't broadcast\n", mID, bID);
		return "031lock is null, failing broadcast";
	}
	if(!conditionLock->isHeldByCurrentNode(mID, bID)){
		DEBUG('v', "machine(%d,%d) is not holding lock(%s), can't broadcast\n", mID, bID, conditionLock->getName());
		return "032lock is not hold by current node";
	}
	if(lock == -1){
		DEBUG('v', "machine(%d,%d) is not lock(%s) related, can't broadcast\n", mID, bID, conditionLock->getName());
		return "1";
	}
	else if(lock != lockID)
	{
		DEBUG('v', "machine(%d,%d) is not lock(%s) related, can't broadcast\n", mID, bID, conditionLock->getName());
		return "035condition is using a different lock";
	}

	// machine is going to signal a condition
	DEBUG('v', "machine(%d,%d) is going to broadcast condition(%s)\n", mID, bID, name);
	
	Message * msg = (Message*)waitQueue->Remove();
	while(msg != NULL){
		int mID2 = msg->machine;
		int bID2 = msg->mailbox;
		delete msg;
		conditionLock->Acquire(mID2, bID2);
		msg = (Message*)waitQueue->Remove();
	} 
	
	lock = -1;
	return "1";

}

//---------------------------------------------
// ServerMV Implementation 
//---------------------------------------------
ServerMV::ServerMV(char * debugName, int array_size, int initValue){
	name = debugName;
	size = array_size;
	data = new int[array_size];
	for(int i=0;i<array_size;i++)
		data[i] = initValue;
}

ServerMV::~ServerMV(){
	delete data;
}

//---------------------------------------------
// Minor functions corresponding to different
// message types
//---------------------------------------------

/* Convert an index to a 4-digit string. ex.'0001'
 * Store the converted string in a char array, here is 't'
 */

void
IndexToString(char * t,   int number){
	if(number >= LOCK_TABLE_SIZE || number <0) 
		return;
	
	if(number > 999)
		sprintf(t, "%d", number);
	else if(number > 99){
		sprintf(t+1, "%d", number);
		t[0]='0';
	}
	else if(number > 9){
		sprintf(t+2, "%d", number);
		t[1]='0';
		t[0]='0';
	}
	else {
		sprintf(t+3, "%d", number);
		t[0]='0';
		t[1]='0';
		t[2]='0';
	}
}

void
CleanServerLockTable(){
	
	for(int i=LOCK_TABLE_SIZE - 1 ; i>=0 ; i--)
	{
		KernelServerLock * klock = ServerLockTable[i];

		if(klock == NULL)
		{
			nextLockIndex = i;
			continue;
		}
		
		if(klock->isDeleted)
		{
			delete klock->lock;							//delete the lock instance related to this kernel lock
			delete klock;
			ServerLockTable[i] = NULL;
			nextLockIndex = i;
			continue;
		}
	}
}

void
CleanServerCVTable(){

	for(int i=CV_TABLE_SIZE -1; i>=0; i--)
	{
		KernelServerCV * kcv = ServerCVTable[i];

		if(kcv == NULL)
		{
			nextCVIndex = i;
			continue;
		}

		if(kcv->isDeleted)
		{
			delete kcv->cv;
			delete kcv;
			ServerCVTable[i] = NULL;
			nextCVIndex = i;
			continue;
		}
	}
}


void
CleanServerMVTable(){

	for(int i=MV_TABLE_SIZE -1; i>=0; i--)
	{
		KernelServerMV * kmv = ServerMVTable[i];

		if(kmv == NULL)
		{
			nextMVIndex = i;
			continue;
		}

		if(kmv->isDeleted)
		{
			delete kmv->mv;
			delete kmv;
			ServerMVTable[i] = NULL;
			nextMVIndex = i;
			continue;
		}
	}
}


// If index passes the validation, it will return NULL pointer
char *
ValidateServerLockIndex(int index){
	if(index<0 || index >= LOCK_TABLE_SIZE) {
		return "023Lock index out of bound";
	}
	
	KernelServerLock * klock = ServerLockTable[index];

	if(klock == NULL){
		return  "028Requested lock doesn't exist";
	}
	if(klock->isDeleted){
		return "031Requested lock has been deleted";
	}
	return NULL;
}

// If index passes the validation, it will return NULL pointer
char *
ValidateServerCVIndex(int index){
	if(index<0 || index >= CV_TABLE_SIZE) {
		return "021CV index out of bound";
	}
	
	KernelServerCV * kcv = ServerCVTable[index];

	if(kcv == NULL){
		return  "026Requested cv doesn't exist";
	}
	if(kcv->isDeleted){
		return "029Requested cv has been deleted";
	}
	return NULL;
}

// If index passes the validation, it will return NULL pointer
char *
ValidateServerMVIndex(int index){
	if(index<0 || index >= MV_TABLE_SIZE) {
		return "021MV index out of bound";
	}
	
	KernelServerMV * kmv = ServerMVTable[index];

	if(kmv == NULL){
		return  "026Requested mv doesn't exist";
	}
	if(kmv->isDeleted){
		return "029Requested mv has been deleted";
	}
	return NULL;
}


void
CreateServerLock(){

	char lenstr[3];
	lenstr[0]=rpc_buffer[2];
	lenstr[1]=rpc_buffer[3];
	lenstr[2]='\0';
	int len = atoi(lenstr);
	char * name = new char[len+1];
	memcpy(name, &rpc_buffer[4], len);
	name[len] = '\0';
	
	DEBUG('v', "Server receives a CREATE_LOCK request with lock name: %s\n", name);

	// search specified lock with its lock name
	// return index if it is found, otherwise create a new lock
	// and return the new index
	
	int index = -1;
	for(int i=0; i<LOCK_TABLE_SIZE;i++)
	{
		if(ServerLockTable[i] != NULL && !ServerLockTable[i]->isDeleted){
			if(!strcmp(ServerLockTable[i]->lock->getName(), name)){
				DEBUG('v', "Server found an existing lock with the same name\n");
				index = i;
				DEBUG('6',"CreateLock :  already exist, index=%2d , name is %s\n", index,name);
				break;
			}
		}
	}

	if(index == -1){
		DEBUG('v', "Server couldn't find an existing lock, create a new one\n");	
		if(nextLockIndex == LOCK_TABLE_SIZE){
			// Reply error message to client that lock table is full
			printf("SERVER ERROR: The lock table on server has been full\n");
			char * reply = "022The lock table is full";
			outPktHdr.to = inPktHdr.from;
			outMailHdr.to = inMailHdr.from;
			outMailHdr.length = strlen(reply) + 1;
			if(netname == serverForwardMID){
			bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
			if ( !success ) {
				printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
				interrupt->Halt();
			 }}
			return;
		}
		
		ServerLock * slock = new ServerLock(name);
		KernelServerLock * klock = new KernelServerLock();
		klock -> lock = slock;
		klock -> isDeleted = false;
		klock -> useCount = 0;
		
		// Add lock into lock table
		ServerLockTable[nextLockIndex] = klock;
		index = nextLockIndex;
		DEBUG('6',"CreateLock : length=%2d, granted index=%2d, name is %s\n", len,index,name);

		nextLockIndex ++;
		while(nextLockIndex < LOCK_TABLE_SIZE && ServerLockTable[nextLockIndex] != NULL)
			nextLockIndex++;

		if(nextLockIndex == LOCK_TABLE_SIZE)
			CleanServerLockTable();
		
	}

	ServerLockTable[index] -> useCount++;
	
	// Send index back to client
	// Message Format: 
	// 0[failed]XX[ErrorMessageLength]XXXXX....\0
	// 1[success]XXXX[LockIndex]\0
	char * reply = "1XXXX";
	IndexToString(reply+1, index);
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}


void
AcquireServerLock(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	char * reply = ValidateServerLockIndex(index);
	if(reply == NULL){
		// Try to acquire lock
		int mID = inPktHdr.from;
		int bID = inMailHdr.from;
		KernelServerLock * klock = ServerLockTable[index];

		reply = klock->lock->Acquire(mID, bID);
	}
	
	// if acquire operation is blocked
	if(reply == NULL) {
		return;
	}
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}
}

void
ReleaseServerLock(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	char * reply = ValidateServerLockIndex(index);
	if(reply == NULL){
		// Try to release lock
		int mID = inPktHdr.from;
		int bID = inMailHdr.from;
		KernelServerLock * klock = ServerLockTable[index];

		reply = klock->lock->Release(mID, bID);
		if(klock->useCount <=0 && klock->lock->getWaitLength()<=0){
			klock->isDeleted = true;
			if(nextLockIndex == LOCK_TABLE_SIZE)
				CleanServerLockTable();
		}
	}
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}
}

void
DestroyServerLock(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	char * reply = ValidateServerLockIndex(index);
	// index has passed the validation
	if(reply == NULL){
		KernelServerLock * klock = ServerLockTable[index];
		if(klock->useCount == 0) {
			reply = "028This lock has been destroyed";
		}
		else{
			klock-> useCount--;
			reply = "1";
		}
		if(klock->useCount==0 && klock->lock->getWaitLength() <= 0)
		{
				klock-> isDeleted = true;
				if(nextLockIndex == LOCK_TABLE_SIZE)
					CleanServerLockTable();
		}
	}
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}
}

void
CreateServerCV(){
	char lenstr[3];
	lenstr[0]=rpc_buffer[2];
	lenstr[1]=rpc_buffer[3];
	lenstr[2]='\0';
	int len = atoi(lenstr);
	char * name = new char[len+1];
	memcpy(name, &rpc_buffer[4], len);
	name[len] = '\0';
	
	DEBUG('v', "Server receives a CREATE_CV request with cv name: %s\n", name);

	// search specified cv with its cv name
	// return index if it is found, otherwise create a new cv
	// and return the new index
	
	int index = -1;
	for(int i=0; i<CV_TABLE_SIZE;i++)
	{
		if(ServerCVTable[i] != NULL && !ServerCVTable[i]->isDeleted){
			if(!strcmp(ServerCVTable[i]->cv->getName(), name)){
				DEBUG('v', "Server found an existing CV with the same name\n");
				index = i;
				DEBUG('6',"CreateCV :  already exist, index=%2d , name is %s\n", index,name);
				break;
			}
		}
	}

	if(index == -1){
		DEBUG('v', "Server couldn't find an existing CV, create a new one\n");	
		if(nextCVIndex == CV_TABLE_SIZE){
			// Reply error message to client that cv table is full
			printf("SERVER ERROR: The cv table on server has been full\n");
			char * reply = "020The cv table is full";
			outPktHdr.to = inPktHdr.from;
			outMailHdr.to = inMailHdr.from;
			outMailHdr.length = strlen(reply) + 1;
			if(netname == serverForwardMID){
			bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
			if ( !success ) {
				printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
				interrupt->Halt();
			 }}
			return;
		}
		
		ServerCV * scv = new ServerCV(name);
		KernelServerCV * kcv = new KernelServerCV();
		kcv -> cv = scv;
		kcv -> isDeleted = false;
		kcv -> useCount = 0;
		
		// Add cv into cv table
		ServerCVTable[nextCVIndex] = kcv;
		index = nextCVIndex;
		DEBUG('6',"CreateCV : length=%2d, granted index=%2d, name is %s\n", len,index,name);

		nextCVIndex ++;
		while(nextCVIndex < CV_TABLE_SIZE && ServerCVTable[nextCVIndex] != NULL)
			nextCVIndex++;

		if(nextCVIndex == CV_TABLE_SIZE)
			CleanServerCVTable();
		
	}

	ServerCVTable[index] -> useCount++;
	
	// Send index back to client
	// Message Format: 
	// 0[failed]XX[ErrorMessageLength]XXXXX....\0
	// 1[success]XXXX[CVIndex]\0
	char * reply = "1XXXX";
	IndexToString(reply+1, index);
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}

void
WaitServerCV(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int lockIndex = atoi(idxstr);
	char * reply = ValidateServerLockIndex(lockIndex);
	if(reply == NULL){
		idxstr[0]=rpc_buffer[6];
		idxstr[1]=rpc_buffer[7];
		idxstr[2]=rpc_buffer[8];
		idxstr[3]=rpc_buffer[9];
		idxstr[4]='\0';
		int cvIndex = atoi(idxstr);
		reply = ValidateServerCVIndex(cvIndex);
		if(reply == NULL){
			// lock index and cv index are valid
			// try to wait on a specific condition
			int mID = inPktHdr.from;
			int bID = inMailHdr.from;
			KernelServerCV * kcv = ServerCVTable[cvIndex];

			reply = kcv->cv->Wait(lockIndex, mID, bID);
		}
	}
	
	// if wait is successfull
	if(reply == NULL)
		return;
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}

void
SignalServerCV(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int lockIndex = atoi(idxstr);
	char * reply = ValidateServerLockIndex(lockIndex);
	if(reply == NULL){
		idxstr[0]=rpc_buffer[6];
		idxstr[1]=rpc_buffer[7];
		idxstr[2]=rpc_buffer[8];
		idxstr[3]=rpc_buffer[9];
		idxstr[4]='\0';
		int cvIndex = atoi(idxstr);
		reply = ValidateServerCVIndex(cvIndex);
		if(reply == NULL){
			// lock index and cv index are valid
			// try to signal a specific condition
			int mID = inPktHdr.from;
			int bID = inMailHdr.from;

			KernelServerCV * kcv = ServerCVTable[cvIndex];
			reply = kcv->cv->Signal(lockIndex, mID, bID);
			if(kcv->useCount <=0 && kcv->cv->getWaitLength()<=0){
				kcv->isDeleted = true;
				if(nextCVIndex == CV_TABLE_SIZE)
					CleanServerCVTable();
			}
		}
	}
	
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}
}

void
BroadcastServerCV(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int lockIndex = atoi(idxstr);
	char * reply = ValidateServerLockIndex(lockIndex);
	if(reply == NULL){
		idxstr[0]=rpc_buffer[6];
		idxstr[1]=rpc_buffer[7];
		idxstr[2]=rpc_buffer[8];
		idxstr[3]=rpc_buffer[9];
		idxstr[4]='\0';
		int cvIndex = atoi(idxstr);
		reply = ValidateServerCVIndex(cvIndex);
		if(reply == NULL){
			// lock index and cv index are valid
			// try to signal a specific condition
			int mID = inPktHdr.from;
			int bID = inMailHdr.from;
			
			KernelServerCV * kcv = ServerCVTable[cvIndex];
			reply = kcv->cv->Broadcast(lockIndex, mID, bID);
			if(kcv->useCount <=0 && kcv->cv->getWaitLength()<=0){
				kcv->isDeleted = true;
				if(nextCVIndex == CV_TABLE_SIZE)
					CleanServerCVTable();
			}
		}
	}
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}

void
DestroyServerCV(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	char * reply = ValidateServerCVIndex(index);
	// index has passed the validation
	if(reply == NULL){
		KernelServerCV * kcv = ServerCVTable[index];
		if(kcv->useCount == 0) {
			reply = "026This cv has been destroyed";
		}
		else {
			kcv-> useCount--;
			reply = "1";
		}
		if(kcv->useCount==0 && kcv->cv->getWaitLength() <= 0)
		{
			kcv-> isDeleted = true;
			if(nextCVIndex == CV_TABLE_SIZE)
				CleanServerCVTable();
		}
	}
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}


void  CreateServerMV(){
	// get name length
	char lenstr[5];
	lenstr[0]=rpc_buffer[2];
	lenstr[1]=rpc_buffer[3];
	lenstr[2]='\0';
	int len = atoi(lenstr);
	
	// get array length
	lenstr[0]=rpc_buffer[4];
	lenstr[1]=rpc_buffer[5];
	lenstr[2]=rpc_buffer[6];
	lenstr[3]=rpc_buffer[7];
	lenstr[4]='\0';
	
	int array_len = atoi(lenstr);
	
//Modified by OceanMaster
	int initValue;
	char * tmp;
	tmp = (char *)&initValue;
	tmp[0]=rpc_buffer[8];
	tmp[1]=rpc_buffer[9];
	tmp[2]=rpc_buffer[10];
	tmp[3]=rpc_buffer[11];
	//DEBUG('6',"Init Value is %d, 0x%08x\n",initValue, initValue);

	char * name = new char[len+1];
	memcpy(name, &rpc_buffer[12], len);
	name[len] = '\0';
		
	DEBUG('v', "Server receives a CREATE_MV request with mv name: %s\n", name);

	// search specified mv with its mv name
	// return index if it is found, otherwise create a new mv
	// and return the new index
	
	int index = -1;
	for(int i=0; i<MV_TABLE_SIZE;i++)
	{
		if(ServerMVTable[i] != NULL && !ServerMVTable[i]->isDeleted){
			if(!strcmp(ServerMVTable[i]->mv->getName(), name)){
				DEBUG('v', "Server found an existing MV with the same name\n");
				index = i;
				DEBUG('6',"CreateMV :  already exist, index=%2d , name is %s\n", index,name);
				break;
			}
		}
	}

	if(index == -1){

		DEBUG('v', "Server couldn't find an existing MV, create a new one\n");	
		if(nextMVIndex == MV_TABLE_SIZE){
			// Reply error message to client that mv table is full
			printf("SERVER ERROR: The mv table on server has been full\n");
			char * reply = "020The mv table is full";
			outPktHdr.to = inPktHdr.from;
			outMailHdr.to = inMailHdr.from;
			outMailHdr.length = strlen(reply) + 1;
			if(netname == serverForwardMID){
			bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
			if ( !success ) {
				printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
				interrupt->Halt();
			 }}
			return;
		}
	
		ServerMV * smv = new ServerMV(name, array_len, initValue);
		KernelServerMV * kmv = new KernelServerMV();
		kmv -> mv = smv;
		kmv -> isDeleted = false;
		kmv -> useCount = 0;
		
		// Add mv into mv table
		ServerMVTable[nextMVIndex] = kmv;
		index = nextMVIndex;

		DEBUG('6',"CreateMV : length=%2d, initValue=%2d, granted index=%2d, name is %s\n", array_len, initValue,index,name);


		nextMVIndex ++;
		while(nextMVIndex < MV_TABLE_SIZE && ServerMVTable[nextMVIndex] != NULL)
			nextMVIndex++;

		if(nextMVIndex == MV_TABLE_SIZE)
			CleanServerMVTable();
		
	}

	ServerMVTable[index] -> useCount++;
	
	// Send index back to client
	// Message Format: 
	// 0[failed]XX[ErrorMessageLength]XXXXX....\0
	// 1[success]XXXX[MVIndex]\0
	char * reply = "1XXXX";
	IndexToString(reply+1, index);
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}


}

void GetServerMVValue(){
	// get index of monitor variable
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	
	// get array index of data
	idxstr[0]=rpc_buffer[6];
	idxstr[1]=rpc_buffer[7];
	idxstr[2]=rpc_buffer[8];
	idxstr[3]=rpc_buffer[9];
	idxstr[4]='\0';
	int array_index = atoi(idxstr);
	
	char * reply = ValidateServerMVIndex(index);
	if(reply == NULL){
		// Try to get value of monitor variable
		KernelServerMV * kmv = ServerMVTable[index];
		if(!kmv->mv->validateBondary(array_index)){
			reply = "030Index of array is out of bound";
		} 
		else {
			int value = kmv->mv->getValue(array_index);
			reply = new char[30];
			reply[0] = '1';
			sprintf(&reply[1], "%d", value);
			DEBUG('6',"GetMV : index=%d, %dth element = %d\n",index, array_index,value);
		}
	}
	
	DEBUG('6',"reply [%s]\n",reply);

	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}

}

void SetServerMVValue(){
	// get index of monitor variable
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	
	// get array index of data
	idxstr[0]=rpc_buffer[6];
	idxstr[1]=rpc_buffer[7];
	idxstr[2]=rpc_buffer[8];
	idxstr[3]=rpc_buffer[9];
	idxstr[4]='\0';
	int array_index = atoi(idxstr);

	// get new value to be set
	int value;
	
	char * tmp;
	tmp = (char *)&value;
	tmp[0]=rpc_buffer[10];
	tmp[1]=rpc_buffer[11];
	tmp[2]=rpc_buffer[12];
	tmp[3]=rpc_buffer[13];
		
	printf("SetMV : index=%d, set %dth element = %d \n", index , array_index, value);

	char * reply = ValidateServerMVIndex(index);
	if(reply == NULL){
		// Try to set value of monitor variable
		KernelServerMV * kmv = ServerMVTable[index];
		if(!kmv->mv->validateBondary(array_index)){
			reply = "030Index of array is out of bound";
		} 
		else {
			kmv->mv->setValue(array_index, value);
			reply = "1";
		}
	}
	
	DEBUG('6',"reply [%s]\n",reply);


	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}
}

void DestroyServerMV(){
	char idxstr[5];
	idxstr[0]=rpc_buffer[2];
	idxstr[1]=rpc_buffer[3];
	idxstr[2]=rpc_buffer[4];
	idxstr[3]=rpc_buffer[5];
	idxstr[4]='\0';
	int index = atoi(idxstr);
	char * reply = ValidateServerMVIndex(index);
	// index has passed the validation
	if(reply == NULL){
		KernelServerMV * kmv = ServerMVTable[index];
		if(kmv->useCount == 0) {
			reply = "026This mv has been destroyed";
		}
		else {
			kmv-> useCount--;
			reply = "1";
		}
		if(kmv->useCount==0)
		{
			kmv-> isDeleted = true;
			if(nextMVIndex == MV_TABLE_SIZE)
				CleanServerMVTable();
		}
	}
	
	outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(reply) + 1;
	if(netname == serverForwardMID){
	bool  success = postOffice->Send(outPktHdr, outMailHdr, reply); 
	if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }}


}


void
InitialServer(){
	
	//serverNum = 5;
	
	ServerLockTable = new KernelServerLock * [LOCK_TABLE_SIZE];	
	ServerCVTable = new KernelServerCV * [CV_TABLE_SIZE];
	ServerMVTable = new KernelServerMV * [MV_TABLE_SIZE];
	LTR = new int64_t[serverNum];
	msgQueue =  new List;
	
	for(int i=0; i<LOCK_TABLE_SIZE; i++)
		ServerLockTable[i] = NULL;
	for(int i=0; i<CV_TABLE_SIZE; i++)
		ServerCVTable[i] = NULL;
	for(int i=0; i<MV_TABLE_SIZE; i++)
		ServerMVTable[i] = NULL;

	for(int i=0; i<serverNum; i++){
		LTR[i] = -1;
	}
}


/**
 *	It is selected server's responsiblity to forward client's messages to all other distributed servers 
 *  Message sent by client has an end '\0', don't remove it
 *	Append client machine ID , mailbox ID, and timestamp after '\0'
 */

void ForwardBehavior(){
	while(1){
		postOffice->Receive(0, &s_inPktHdr, &s_inMailHdr, s_buffer);
		char* clientMID = (char*)&s_inPktHdr.from;
		char* clientBID = (char*)&s_inMailHdr.from;

		// Append client machineID and Server
		int ptr = s_inMailHdr.length;
		s_buffer[ptr+0] = clientMID[3];
		s_buffer[ptr+1] = clientBID[3];

		// Append server timestamp
		//time_t t = getCurTime();
		unsigned t = getCurTime();
		
		//	t = time(NULL);
		char* stamp = (char*)&t;
		s_buffer[ptr+2] = stamp[0];
		s_buffer[ptr+3] = stamp[1];
		s_buffer[ptr+4] = stamp[2];
		s_buffer[ptr+5] = stamp[3];

		if(ptr + 6 >40)
			printf("ERROR: Forward Message is too long!!!!");

		DEBUG('f', "Server[%d] forward Client [MID%d,BID%d] message to all servers with timestamp[%lu]\n", netname, s_inPktHdr.from, s_inMailHdr.from, t);	
		for(int i=0; i<serverNum; i++)
		{
			s_outPktHdr.to = i;		
			s_outMailHdr.to = 2;		
			s_outMailHdr.from = 1;
			s_outMailHdr.length = ptr + 6;

			// Forward message to all servers, including itself
			bool success = postOffice->Send(s_outPktHdr, s_outMailHdr, s_buffer); 
		
			if(printLog)
				cout<<"Forward Message to Server#"<<i<<" from Server#"<<netname<<(success?" SUCCESS":" FAILED")<<endl;
		}
	}
}

int64_t
FindSmallestTimestamp(bool p)
{
	if(p){
		printf("------------------------------------------------------------------\nKEY VALUE:\t");
		for(int i=0; i< serverNum; i++){
			cout<< LTR[i]<<'\t';
		}
		printf("\nTIME STAMP:\t");
		for(int i=0; i< serverNum; i++){
			if(LTR[i]<0)
				cout<< "-1\t";
			else{
				time_t t = (LTR[i]-i)/10;
				cout<<  t <<'\t';
			}
		}
		printf("\n------------------------------------------------------------------\n");
	}
	int64_t smallest = LTR[0];
	for(int i=1; i<serverNum; i++){
		if(LTR[i] <= smallest){
			smallest = LTR[i];
		}
	}
	return smallest;
}

void
ProcessRequest(){

		char typestr[3];
		typestr[0] = rpc_buffer[0];
		typestr[1] = rpc_buffer[1];
		typestr[2] = '\0';
		int type = atoi(typestr);
	
		printf("Processed type:%s",typestr);
		// Process message
		switch(type){
		case 0:
				  CreateServerLock();
				  break;
		case 1:
				  AcquireServerLock();
				  break;
		case 2:
				  ReleaseServerLock();
				  break;
		case 3:
				  DestroyServerLock();
				  break;
		case 4:
				  CreateServerCV();
				  break;
		case 5:
				  WaitServerCV();
				  break;
		case 6:
				  SignalServerCV();
				  break;
		case 7:
				  BroadcastServerCV();
				  break;
		case 8:
				  DestroyServerCV();
				  break;
		case 9:	  
				  CreateServerMV();
				  break;
		case 10:  
				  GetServerMVValue();
				  break;
		case 11:
				  SetServerMVValue();
				  break;
		case 12:
				  DestroyServerMV();
				  break;
		default:
				  printf("ERROR: Cannot recognize the message type\n");
				  interrupt->Halt();
				  break;
		}
}


void TotalOrdering(){

	while(1){
		postOffice->Receive(2, &inPktHdr, &inMailHdr, rpc_buffer);
		int forwardMID = inPktHdr.from;
		int forwardBID = inMailHdr.from;
		int clientMID, clientBID;
		
		unsigned t; // changed by Nick
		//time_t t;
		int64_t key;
	
		char typestr[3];
		typestr[0] = rpc_buffer[0];
			typestr[1] = rpc_buffer[1];
		typestr[2] = '\0';
		int type = atoi(typestr);
		
		printf("Server[%d] receive message from server[%d] with type:%d\n", netname, forwardMID, type);
			
		DEBUG('f', "Server[%d] receive message from server[%d] with type:%d\n", netname, forwardMID, type);
		
		// Send a response message with timestamp to all servers
		if(type >= 0){				//It's not a response message
			
			t = getCurTime();

			//t = time(NULL);
			char * buffer = new char[8];
			char* stamp = (char*)&t;
			
			buffer[0] = '-';
			buffer[1] = '1';
			buffer[2] = stamp[0];
			buffer[3] = stamp[1];
			buffer[4] = stamp[2];
			buffer[5] = stamp[3];

			DEBUG('f', "Server[%d] send response message to all server with timestamp[%lu]\n", netname, t);		
			for(int i=0; i<serverNum; i++){
				outPktHdr.to = i;		
				outMailHdr.to = 2;		// mailbox is 1 for sending or receiving forwarded message
				outMailHdr.from = 1;
				outMailHdr.length = 6;

				bool success = postOffice->Send(outPktHdr, outMailHdr, buffer); 
			}
		
			int ptr = inMailHdr.length - 6;
			char * mm = (char*)&clientMID;	// client machine ID
			char * bb = (char*)&clientBID;	// client mailbox ID
			char * tt = (char*)&t;
		
			mm[0] = '\0';
			mm[1] = '\0';
			mm[2] = '\0';
			mm[3] = rpc_buffer[ptr+0];
			bb[0] = '\0';
			bb[1] = '\0';
			bb[2] = '\0';
			bb[3] = rpc_buffer[ptr+1];
			tt[0] = rpc_buffer[ptr+2];
			tt[1] = rpc_buffer[ptr+3];
			tt[2] = rpc_buffer[ptr+4];
			tt[3] = rpc_buffer[ptr+5];
	
		DEBUG('f', "Server[%d] process Server[%d] forwarded message with timestamp[%lu] sent by Client[MID%d,BID%d]\n", netname, forwardMID, t, clientMID, clientBID);
	
			// Put the requested message in the message queue
			char * nbuffer = new char[MaxMailSize];
			key = (int64_t)t * 10 + forwardMID;
			ASSERT(key >=0);	// changed by Nick	
			if(printLog)
				cout<<"Generate KEY:"<<key<<endl<<"Received a Forward Message from Server#"<<forwardMID<<endl;

			
			// Change rpc_buffer timestamp bit to forward netname
			// So the message looks like: clientMsg____clientMID____clientBID____forwardServerID
			char* ss = (char*)&forwardMID;
			rpc_buffer[ptr+2]  = ss[0];
			rpc_buffer[ptr+3]  = ss[1];
			rpc_buffer[ptr+4] = ss[2];
			rpc_buffer[ptr+5] = ss[3];
			
			memcpy(nbuffer, rpc_buffer, MaxMailSize);
			msgQueue->SortedInsert(new ServerMsg(nbuffer,ptr), key);
		}
		else {								//It's a response message
			char * tt = (char*)&t;
			tt[0] = rpc_buffer[2];
			tt[1] = rpc_buffer[3];
			tt[2] = rpc_buffer[4];
			tt[3] = rpc_buffer[5];
			DEBUG('f', "Server[%d] process Server[%d] response message with timestamp[%lu]\n", netname, forwardMID, t);
			key = (int64_t)t * 10 + forwardMID;
			ASSERT(key >=0 ) // changed by Nick	
			if(printLog)
				cout<<"Generate KEY:"<<key<<endl<<"Received a Response Message from Server#"<<forwardMID<<endl;
		}
		
		// Update the last timestamp received table
		LTR[forwardMID] = key;

		// Scan the LTR table and extract the smallest timestamp		
		int64_t smallest = FindSmallestTimestamp(printLog);
		
		if(printLog)
			cout << "process message in queue: get smallest timestamp:" << smallest <<endl;	

		// Process any message in our pending queue having a timestamp less or equal than the smallest value
		int64_t firstKey;
		ServerMsg * sMsg = (ServerMsg*)msgQueue->SortedRemove((int64_t*)&firstKey);
		if (sMsg==NULL)
		{
			printf("what the fuck!\n");
		}
		cout<<"FirstKey:"<<firstKey<<","<<"smallest:"<<smallest<<endl;
		while(sMsg != NULL && (firstKey/10 <= smallest/10))
		{
			char * firstMsg = sMsg->msg;
			printf("Message to be processed is:%s\n",firstMsg);
			int ptr = sMsg->msg_len;
			memcpy(rpc_buffer, firstMsg, MaxMailSize);	// get client message 
			delete firstMsg;
			delete sMsg;

			char * mm = (char*)&(inPktHdr.from);		// get client machine ID
			char * bb = (char*)&(inMailHdr.from);		// get client mailbox ID
			char * ss = (char*)&serverForwardMID;
			
			mm[0] = '\0';
			mm[1] = '\0';
			mm[2] = '\0';
			mm[3] = rpc_buffer[ptr+0];
			bb[0] = '\0';
			bb[1] = '\0';
			bb[2] = '\0';
			bb[3] = rpc_buffer[ptr+1];
			ss[0] = rpc_buffer[ptr+2];
			ss[1] = rpc_buffer[ptr+3];
			ss[2] = rpc_buffer[ptr+4];
			ss[3] = rpc_buffer[ptr+5];
		
			DEBUG('f',"process message from client[MID%d,BID%d]\n", inPktHdr.from, inMailHdr.from);
			if(printLog)
				printf("message content: %s\n", rpc_buffer);

			ProcessRequest();
		
			// Retreive the next message
			sMsg = (ServerMsg*)msgQueue->SortedRemove((int64_t*)&firstKey);
		}
		
		// Put the last message back to queue
		if(sMsg!=NULL && (firstKey/10 > smallest/10))
		{
			msgQueue->SortedInsert(sMsg, firstKey);
		}

	}
}

// Just for testing server logic
void
StartClient(){
	char *data = "009hellolock";
    char buffer[MaxMailSize];
	printf("Hi, I'm a client, Sending AcquireLock message:%s\n", data);
	
    // construct packet, mail header for original message
    // To: destination machine, mailbox 0
    // From: our machine, reply to: mailbox 1
    outPktHdr.to = 0;		
    outMailHdr.to = 0;
    outMailHdr.from = 21;
    outMailHdr.length = strlen(data) + 1;

    // Send the first message
    bool success = postOffice->Send(outPktHdr, outMailHdr, data); 


}


void
StartServer()//(int farAddr)
{

/*	struct timeval tempo;
	gettimeofday(&tempo, NULL);
	long cur_time = tempo.tv_usec;
*/

	InitialServer();
	printf("[Total:%d] Server starts up with machineID: %d\n", serverNum, netname);

//modified by Oceanmaster
//If serverNum <= 1, needn't do total ordering algorithm.	
	if(serverNum > 1)
	{
		Thread * t = new Thread("Forwarding");
		t->Fork((VoidFunctionPtr)ForwardBehavior, 0);
		// Server start to process the message it receives, and implement total ordering
		TotalOrdering();
	}
	else
	while(1)
	{
		serverForwardMID = netname;	
		// Receive a message from mailbox 0
		postOffice->Receive(0, &inPktHdr, &inMailHdr, rpc_buffer);
		char typestr[3];
		typestr[0] = rpc_buffer[0];
		typestr[1] = rpc_buffer[1];
		typestr[2] = '\0';
		int type = atoi(typestr);
		
		// Process message
		switch(type)
		{
		case 0:
				  CreateServerLock();
				  break;
		case 1:
				  AcquireServerLock();
				  break;
		case 2:
				  ReleaseServerLock();
				  break;
		case 3:
				  DestroyServerLock();
				  break;
		case 4:
				  CreateServerCV();
				  break;
		case 5:
				  WaitServerCV();
				  break;
		case 6:
				  SignalServerCV();
				  break;
		case 7:
				  BroadcastServerCV();
				  break;
		case 8:
				  DestroyServerCV();
				  break;
		case 9:	  
				  CreateServerMV();
				  break;
		case 10:  
				  GetServerMVValue();
				  break;
		case 11:
				  SetServerMVValue();
				  break;
		case 12:
				  DestroyServerMV();
				  break;
		default:
				  printf("ERROR: Cannot recognize the message type\n");
				  interrupt->Halt();
				  break;
		}
	}
	
	/*
	PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
    char *data = "Hello there!";
    char *ack = "Got it!";
    char buffer[MaxMailSize];

    // construct packet, mail header for original message
    // To: destination machine, mailbox 0
    // From: our machine, reply to: mailbox 1
    outPktHdr.to = farAddr;		
    outMailHdr.to = 0;
    outMailHdr.from = 1;
    outMailHdr.length = strlen(data) + 1;

    // Send the first message
    bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the first message from the other machine
    postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Send acknowledgement to the other machine (using "reply to" mailbox
    // in the message that just arrived
    outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(ack) + 1;
    success = postOffice->Send(outPktHdr, outMailHdr, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the ack from the other machine to the first message we sent.
    postOffice->Receive(1, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);
	*/
    
	// Then we're done!
    interrupt->Halt();
}
